package com.mapperdb.binding;

import java.util.Map;

import org.apache.ibatis.binding.BindingException;
import org.apache.ibatis.binding.MapperProxyFactory;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.mapperdb.builder.annotation.AnntBuilder;
import com.mapperdb.builder.annotation.MapperAnntBuilder;
import com.mapperdb.util.ReflectUtils;

/**
 * MapperRegistry 代理类
 * @author Administrator
 *
 */
public class MapperRegistryProxy {
	private MapperRegistry mapperRegistry;
	private Configuration configuration;
	private Map<Class<?>, MapperProxyFactory<?>> knownMappers;

	public MapperRegistryProxy(SqlSession sqlSession) {
		this(sqlSession.getConfiguration());
	}

	public MapperRegistryProxy(SqlSessionFactory sqlSessionFactory) {
		this(sqlSessionFactory.getConfiguration());
	}

	public MapperRegistryProxy(Configuration configuration) {
		this.setConfiguration(configuration);
	}

	public MapperRegistryProxy() {

	}

	public static MapperRegistryProxy use(SqlSession sqlSession) {
		return new MapperRegistryProxy(sqlSession.getConfiguration());
	}

	public static MapperRegistryProxy use(SqlSessionFactory sqlSessionFactory) {
		return new MapperRegistryProxy(sqlSessionFactory);
	}

	public static MapperRegistryProxy use(MappedStatement ms) {
		return new MapperRegistryProxy(ms.getConfiguration());
	}

	public void setConfiguration(Configuration configuration) {
		// 初始化 
		if (mapperRegistry == null) {
			this.mapperRegistry = configuration.getMapperRegistry();
			this.configuration = configuration;
			this.knownMappers = ReflectUtils.get(mapperRegistry, "knownMappers");
		}
	}

	public <T> boolean hasMapper(Class<T> type) {
		return mapperRegistry.hasMapper(type);
	}

	public <T> void addMapper(Class<T> type) {
		if (type.isInterface()) {
			if (hasMapper(type)) {
				throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
			}
			boolean loadCompleted = false;
			try {
				knownMappers.put(type, new MapperProxyFactory<T>(type));
				// 注解解析
				AnntBuilder parser = new MapperAnntBuilder(configuration, type);
				parser.parse();
				loadCompleted = true;
			} finally {
				if (!loadCompleted) {
					knownMappers.remove(type);
				}
			}
		}
	}

	public <T> void addMapper(String className) {
		this.addMapper(ReflectUtils.forName(className));
	}

	public void addMappers(String packageName) {
		mapperRegistry.addMappers(packageName);
	}
}
